package com.kakarote.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.google.common.collect.Lists;
import com.kakarote.admin.common.AdminCodeEnum;
import com.kakarote.admin.entity.BO.AdminDeptBO;
import com.kakarote.admin.entity.BO.AdminDeptQueryBO;
import com.kakarote.admin.entity.BO.DeptVO;
import com.kakarote.admin.entity.PO.*;
import com.kakarote.admin.entity.VO.AdminDeptRoleVO;
import com.kakarote.admin.entity.VO.AdminDeptVO;
import com.kakarote.admin.mapper.AdminDeptMapper;
import com.kakarote.admin.service.*;
import com.kakarote.common.log.entity.OperationLog;
import com.kakarote.core.common.Const;
import com.kakarote.core.common.enums.SystemCodeEnum;
import com.kakarote.core.entity.BasePage;
import com.kakarote.core.entity.PageEntity;
import com.kakarote.core.entity.QueryParentDeptBO;
import com.kakarote.core.entity.UserInfo;
import com.kakarote.core.exception.CrmException;
import com.kakarote.core.feign.admin.entity.SimpleDept;
import com.kakarote.core.servlet.BaseServiceImpl;
import com.kakarote.core.utils.RecursionUtil;
import com.kakarote.core.utils.UserCacheUtil;
import com.kakarote.core.utils.UserUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 部门表 服务实现类
 * </p>
 * @author zhangzhiwei
 * @since 2020-04-27
 */
@Service
public class AdminDeptServiceImpl extends BaseServiceImpl<AdminDeptMapper, AdminDept> implements IAdminDeptService {

    @Resource IAdminUserService adminUserService;
    @Resource IAdminDeptRoleService adminDeptRoleService;
    @Resource IAdminRoleService adminRoleService;
    @Resource IAdminDeptService adminDeptService;
    @Resource IAdminUserRoleService adminUserRoleService;






    /**
     * 查询部门树
     *
     * @param queryBO 上级ID
     * @return data
     */
    @Override
    public List<AdminDeptVO> queryDeptTree(AdminDeptQueryBO queryBO) {
        //@author qun.xu @desc 数据权限为当前机构
        if(queryBO.getId()==null){
            queryBO.setId(this.getLogicDeptId());
        }
        // 组织类型
        String deptType = "tree";
        if (deptType.equals(queryBO.getType())) {
            List<AdminDept> adminDeptList = getBaseMapper().queryDeptList();
            List<AdminDeptVO> childListTree = RecursionUtil.getChildListTree(adminDeptList, "parentId", queryBO.getId(), "deptId", "children", AdminDeptVO.class);
            //当前用户下的机构
            AdminDept adminDept = baseMapper.selectById(queryBO.getId());
            AdminDeptVO root = new AdminDeptVO(adminDept);
            root.setChildren(childListTree);
            return Lists.newArrayList(root);
        }
        List<AdminDept> adminDeptList = list();
        // 行为
        String action = "update";
        if (action.equals(queryBO.getType())) {
            List<Long> ids = RecursionUtil.getChildList(adminDeptList, "parentId", queryBO.getId(), "deptId", "deptId");
            adminDeptList.removeIf(dept -> ids.contains(dept.getDeptId()));
        }
        return adminDeptList.stream().map(obj -> BeanUtil.copyProperties(obj, AdminDeptVO.class)).collect(Collectors.toList());
    }

    /**
     * 查询部门下属部门
     *
     * @param parentId 上级ID
     * @return data
     */
    @Override
    public List<Long> queryChildDept(Long parentId) {
        return RecursionUtil.getChildList(list(), "parentId", parentId, "deptId", "deptId");
    }

    /**
     * 新增部门
     *
     * @param adminDeptBO 部门信息
     * @return
     */
    @Override
    public OperationLog addDept(AdminDeptBO adminDeptBO) {
        //parentId为0的部门只能存在一个
        if (0L == adminDeptBO.getParentId()) {
            throw new CrmException(SystemCodeEnum.SYSTEM_NO_VALID);
        }
        AdminDept adminDept = BeanUtil.copyProperties(adminDeptBO, AdminDept.class);
        save(adminDept);
        OperationLog operationLog = new OperationLog();
        operationLog.setOperationObject(adminDept.getName());
        operationLog.setOperationInfo("新建部门：" + adminDept.getName());
        return operationLog;
    }

    /**
     * 修改部门
     *
     * @param adminDeptBO 部门信息
     */
    @Override
    public OperationLog setDept(AdminDeptBO adminDeptBO) {
        List<Long> deptIdList = queryChildDept(adminDeptBO.getDeptId());
        deptIdList.add(adminDeptBO.getDeptId());
        if (deptIdList.contains(adminDeptBO.getParentId())) {
            throw new CrmException(AdminCodeEnum.ADMIN_PARENT_DEPT_ERROR);
        }
        AdminDept adminDept = getById(adminDeptBO.getDeptId());
        //pid为0的部门只能存在一个
        if ((!adminDept.getParentId().equals(0L)) && adminDeptBO.getParentId().equals(0L)) {
            throw new CrmException(SystemCodeEnum.SYSTEM_NO_VALID);
        }
        lambdaUpdate()
                .set(AdminDept::getName, adminDeptBO.getName())
                .set(AdminDept::getParentId, adminDeptBO.getParentId())
                .set(AdminDept::getOwnerUserId, adminDeptBO.getOwnerUserId())
                .eq(AdminDept::getDeptId, adminDept.getDeptId())
                .update();
        List<AdminUser> userList = adminUserService
                .lambdaQuery()
                .select(AdminUser::getUserId)
                .eq(AdminUser::getDeptId, adminDeptBO.getDeptId())
                .list();
        for (AdminUser user : userList) {
            UserCacheUtil.removeUserCache(user.getUserId());
        }
        //清除缓存
        UserCacheUtil.removeDeptCache(adminDept.getDeptId());
        OperationLog operationLog = new OperationLog();
        operationLog.setOperationObject(adminDept.getName());

        List<String> updateRecord = new ArrayList<>();
        if (ObjectUtil.notEqual(adminDeptBO.getName(), adminDept.getName())) {
            updateRecord.add("将部门名称由" + adminDept.getName() + "改为" + adminDeptBO.getName());
        }
        if (ObjectUtil.notEqual(adminDeptBO.getParentId(), adminDept.getParentId())) {
            String deptName = ObjectUtil.defaultIfBlank(UserCacheUtil.getDeptName(adminDept.getParentId()), "空");
            String deptName1 = ObjectUtil.defaultIfBlank(UserCacheUtil.getDeptName(adminDeptBO.getParentId()), "空");
            updateRecord.add("将部门上级由" + deptName + "改为" + deptName1);
        }
        if (ObjectUtil.notEqual(adminDeptBO.getOwnerUserId(), adminDept.getOwnerUserId())) {
            String userName = ObjectUtil.defaultIfBlank(UserCacheUtil.getUserName(adminDept.getOwnerUserId()), "空");
            String userName1 = ObjectUtil.defaultIfBlank(UserCacheUtil.getUserName(adminDeptBO.getOwnerUserId()), "空");
            updateRecord.add("将部门负责人由" + userName + "改为" + userName1);
        }
        if (updateRecord.isEmpty()) {
            operationLog.setOperationInfo("无修改信息");
        } else {
            operationLog.setOperationInfo(JSONUtil.toJsonStr(updateRecord));
        }
        return operationLog;
    }

    /**
     * 删除部门
     *
     * @param deptId 部门ID
     * @return
     */
    @Override
    public OperationLog deleteDept(Long deptId) {
        boolean userExist = adminUserService.lambdaQuery().eq(AdminUser::getDeptId, deptId).exists();
        if (userExist) {
            throw new CrmException(AdminCodeEnum.ADMIN_DEPT_REMOVE_EXIST_USER_ERROR);
        }
        boolean exists = lambdaQuery().eq(AdminDept::getParentId, deptId).exists();
        if (exists) {
            throw new CrmException(AdminCodeEnum.ADMIN_DEPT_REMOVE_EXIST_DEPT_ERROR);
        }

        AdminDept dept = getById(deptId);
        removeById(deptId);
        UserCacheUtil.removeDeptCache(deptId);

        OperationLog operationLog = new OperationLog();
        operationLog.setOperationObject(dept.getName());
        operationLog.setOperationInfo("删除部门：" + dept.getName());
        return operationLog;
    }

    /**
     * 根据ids查询用户信息
     *
     * @param ids id列表
     * @return data
     */
    @Override
    public List<SimpleDept> queryDeptByIds(List<Long> ids) {
        if (ids.isEmpty()) {
            return new ArrayList<>();
        }
        LambdaQueryChainWrapper<AdminDept> wrapper = lambdaQuery().select(AdminDept::getDeptId, AdminDept::getName, AdminDept::getParentId);
        if (ids.size() == 1) {
            wrapper.eq(AdminDept::getDeptId, ids.get(0));
        } else {
            wrapper.in(AdminDept::getDeptId, ids);
        }
        return wrapper.list().stream().map(obj -> {
            SimpleDept simpleDept = new SimpleDept();
            simpleDept.setId(obj.getDeptId());
            simpleDept.setName(obj.getName());
            simpleDept.setParentId(obj.getParentId());
            return simpleDept;
        }).collect(Collectors.toList());
    }

    @Override
    public List<DeptVO> queryDeptUserList() {
        return getBaseMapper().queryDeptUserList();
    }



    @Override
    public BasePage<AdminDeptRoleVO> queryDeptByRole(Long roleId, PageEntity page) {
        BasePage<AdminDeptRoleVO> list = getBaseMapper().queryDeptByRole(page.parse(), roleId);
        list.getRecords().forEach(e -> {
            Long deptId = e.getDeptId();

            Set<Long> collect = adminDeptRoleService.lambdaQuery()
                    .eq(AdminDeptRole::getDeptId, deptId)
                    .select(AdminDeptRole::getRoleId)
                    .list()
                    .stream().map(AdminDeptRole::getRoleId).collect(Collectors.toSet());

            List<AdminRole> roleList = adminRoleService.listByIds(collect);
            e.setRoleId(StrUtil.join(Const.SEPARATOR, collect));
            if (ObjectUtil.isNotEmpty(roleList)) {
                String roleNames = roleList.stream().map(AdminRole::getRoleName).collect(Collectors.joining(Const.SEPARATOR));
                e.setRoleName(roleNames);
            }
        });
        return list;
    }

    @Override
    public List<Long> queryParentDeptIdByLevel(QueryParentDeptBO queryBO) {
        List<Long> deptIds = new ArrayList<>();
        //查询出全部部门
        List<AdminDept> deptList = lambdaQuery().list();
        Integer level = queryBO.getLevel();
        Long deptId = queryBO.getDeptId();
        return this.queryParentByLevel(deptIds, deptList, deptId, level);
    }

    @Override
    public void setDeptSort(List<Long> deptIds) {
        List<AdminDept> deptList = new ArrayList<>();
        for (int i = 0; i < deptIds.size(); i++) {
            Long aLong = deptIds.get(i);
            AdminDept adminDept = new AdminDept();
            adminDept.setDeptId(aLong);
            adminDept.setNum(i + 1);
            deptList.add(adminDept);
        }
        updateBatchById(deptList);
    }


    private List<Long> queryParentByLevel(List<Long> deptIds, List<AdminDept> deptList, Long deptId, Integer level) {
        if (level <= 0) {
            return deptIds;
        }

        AdminDept currentUser = deptList.stream().filter(dept -> ObjectUtil.equal(deptId, dept.getDeptId())).findFirst().orElse(null);
        if (ObjectUtil.isNotNull(currentUser)) {
            Long parentId = currentUser.getParentId();
            if (ObjectUtil.isNotNull(parentId) && ObjectUtil.notEqual(0L, parentId)) {
                deptIds.add(parentId);

                level--;
                if (level == 0) {
                    AdminDept adminDept = deptList.stream().filter(dept -> ObjectUtil.equal(deptId, dept.getDeptId())).findFirst().orElse(null);
                    if (ObjectUtil.isNotNull(adminDept)) {
                        deptIds.add(adminDept.getParentId());
                    }
                    return deptIds;
                } else {
                    return queryParentByLevel(deptIds, deptList, parentId, level);
                }
            }
        }
        return deptIds;
    }



    @Override
    public Long getLogicDeptId(){
        UserInfo user =  UserUtil.getUser();
        if(UserUtil.isGroup()){
            AdminDept adminDept =   this.getById(user.getDeptId());
            return adminDept.getParentId();
        }else{
            return user.getDeptId();
        }
    }


    @Override
    public List<Long> querySameLevelDeptId(Long deptId) {
        if (ObjectUtil.isNotNull(deptId)) {
            AdminDept dept = lambdaQuery().eq(AdminDept::getDeptId, deptId).one();
            if (ObjectUtil.isNotNull(dept)) {
                List<AdminDept> depts = lambdaQuery().eq(AdminDept::getParentId, dept.getParentId()).list();
                if (ObjectUtil.isNotEmpty(depts)) {
                    return depts.stream().map(AdminDept::getDeptId).collect(Collectors.toList());
                }
            }
        }
        return new ArrayList<>();
    }

    @Override
    public List<SimpleDept> queryDeptList() {
        LambdaQueryChainWrapper<AdminDept> wrapper = lambdaQuery().select(AdminDept::getDeptId, AdminDept::getName, AdminDept::getParentId, AdminDept::getDeptType);
        return wrapper.list().stream().map(obj -> {
            SimpleDept simpleDept = new SimpleDept();
            simpleDept.setId(obj.getDeptId());
            simpleDept.setName(obj.getName());
            simpleDept.setParentId(obj.getParentId());
            simpleDept.setDeptType(obj.getDeptType());
            return simpleDept;
        }).collect(Collectors.toList());
    }

    @Override
    public Boolean queryDeptIsExistRole(Long deptId, Long label) {
        List<AdminUser> userList = adminUserService.lambdaQuery().eq(AdminUser::getDeptId, deptId).list();
        if (ObjectUtil.isNotEmpty(userList)) {
            List<AdminRole> roleList = adminRoleService.lambdaQuery().eq(AdminRole::getLabel, label).list();
            if (ObjectUtil.isNotEmpty(roleList)) {
                List<Long> userIdList = userList.stream().map(AdminUser::getUserId).collect(Collectors.toList());
                List<Long> roleIdList = roleList.stream().map(AdminRole::getRoleId).collect(Collectors.toList());
                List<AdminUserRole> list = adminUserRoleService.lambdaQuery().in(AdminUserRole::getUserId, userIdList).in(AdminUserRole::getRoleId, roleIdList).list();
                if (ObjectUtil.isNotEmpty(list)){
                    return Boolean.TRUE;
                }
            }
        }
        return Boolean.FALSE;
    }
}
